/*
 *  Copyright 2005 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.model.forum;

import com.blandware.atleap.model.core.ContentLocale;
import com.blandware.atleap.model.core.Page;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>Class that represents a forum. Forum may contain other subforums.
 * </p>
 * <p><a href="Forum.java.html"><i>View source</i></a></p>
 *
 * @author Roman Puchkovskiy <a href="mailto:roman.puchkovskiy@blandware.com">
 *         &lt;roman.puchkovskiy@blandware.com&gt;</a>
 * @version $Revision: 1.8 $ $Date: 2007/12/21 18:42:34 $
 * @struts.form include-all="false" extends="BaseForm"
 * @hibernate.joined-subclass table="`al_forum_forum`" lazy="false"
 * @hibernate.joined-subclass-key column="`page_id`"
 */
public class Forum extends Page {

    /**
     * Annotation to the forum
     */
    protected String annotation = null;

    /**
     * Represents a forum language
     */
    protected ContentLocale language = null;

    /**
     * Parent forum (if this is root forum, this is <code>null</code>)
     */
    protected Forum parent = null;

    /**
     * Forums for which this is parent
     */
    protected List childForums = new ArrayList();

    /**
     * Position of this forum
     */
    protected Integer position;

    /**
     * Topics that belong to this forum
     */
    protected List topics = new ArrayList();

    /**
     * Number of topics in this forum
     */
    protected Integer numberOfTopics = null;

    /**
     * Number of replies in all topics in this forum
     */
    protected Integer numberOfReplies = null;

    /**
     * Last post in this forum
     */
    protected Post lastPost = null;

    /**
     * List of forum subscriptions that relate to this forum
     */
    protected List forumSubscriptions = new ArrayList();

    /**
     * This map maps username to <code>Boolean.TRUE</code> if and only if
     * that user is subscribed to this topic
     */
    protected Map usersSubscribed = new HashMap();

    /**
     * Creates an instance of Forum.
     */
    public Forum() {
    }

    /**
     * Returns first value contained in title map (it should be the same for all,
     * actually, so this method returns title as a single value, not a map).
     *
     * @return title
     * @struts.form-field
     * @struts.validator type="required"
	 * @struts.validator-args arg0resource="forum.forum.form.title"
     */
    public String getSingleTitle() {
        if (title == null || title.isEmpty()) {
            return null;
        }
        return (String) title.values().toArray()[0];
    }

    /**
     * Returns forum annotation.
     *
     * @return annotation
     * @struts.form-field
     */
    public String getAnnotation() {
        return annotation;
    }

    /**
     * Sets forum annotation.
     *
     * @param annotation annotation to set
     */
    public void setAnnotation(String annotation) {
        this.annotation = annotation;
    }

    /**
     * Returns forum language
     *
     * @return language
     * @struts.form-field
	 * @hibernate.many-to-one column="`language`" not-null="true"
     * outer-join="false" lazy="false"
     */
    public ContentLocale getLanguage() {
        return language;
    }

    /**
     * Sets forum language
     *
     * @param language language to set
     */
    public void setLanguage(ContentLocale language) {
        this.language = language;
    }

    /**
     * Returns parent forum. If this is root forum, returns <code>null</code>.
     *
     * @return parent or <code>null</code>
     * @hibernate.many-to-one column="`parent_id`" not-null="false"
     * outer-join="false" lazy="false"
     */
    public Forum getParent() {
        return parent;
    }

    /**
     * Sets parent forum.
     *
     * @param parent parent forum to set
     */
    public void setParent(Forum parent) {
        this.parent = parent;
    }

    /**
     * Returns list of child forums.
     *
     * @return child forums list
     * @hibernate.bag name="childForums" inverse="true" lazy="true"
     * cascade="delete" outer-join="false"
     * order-by="`pos`"
	 * @hibernate.collection-key column="`parent_id`"
	 * @hibernate.collection-one-to-many class="com.blandware.atleap.model.forum.Forum"
     */
    public List getChildForums() {
        return childForums;
    }

    /**
     * Sets list of child forums.
     *
     * @param childForums forums to set
     */
    public void setChildForums(List childForums) {
        this.childForums = childForums;
    }

    /**
     * Adds a child forum to this one.
     *
     * @param forum forum to add
     */
    public void addChildForum(Forum forum) {
        this.childForums.add(forum);
        forum.setParent(this);
    }

    /**
     * Updates changed child forum.
     *
     * @param forum the child forum to be updated
     * @return child forum that has been replaced
     */
	public Forum updateChildForum(Forum forum) {
        Forum oldChildForum = null;
		if ( !forum.getParent().equals(this) ) {
            int index = forum.getParent().childForums.indexOf(forum);
            if (index != -1)
                oldChildForum = (Forum) forum.getParent().childForums.remove(index);
			childForums.add(forum);
			forum.setParent(this);
		}
        return oldChildForum;
	}

    /**
     * Removes a child forum from this one.
     *
     * @param forum forum to remove
     */
    public void removeChildForum(Forum forum) {
        this.childForums.remove(forum);
    }

    /**
     * Returns forum position
     *
     * @return position
     * @hibernate.property
	 * @hibernate.column name="`pos`" not-null="true" unique="false"
     */
    public Integer getPosition() {
        return position;
    }

    /**
     * Sets forum position
     *
     * @param position position to set
     */
    public void setPosition(Integer position) {
        this.position = position;
    }

    /**
     * Returns a list of topics that belong to this forum
     *
     * @return list of topics
     * @hibernate.bag name="topics" inverse="true" lazy="true" cascade="delete"
     * outer-join="false"
	 * @hibernate.collection-key column="`forum_id`"
	 * @hibernate.collection-one-to-many class="com.blandware.atleap.model.forum.Topic"
     */
    public List getTopics() {
        return topics;
    }

    /**
     * Sets a list of topics
     *
     * @param topics list of topics to set
     */
    public void setTopics(List topics) {
        this.topics = topics;
    }

    /**
     * Adds a topic.
     *
     * @param topic topic to add
     */
    public void addTopic(Topic topic) {
        this.topics.add(topic);
        topic.setForum(this);
    }

    /**
     * Removes a topic.
     *
     * @param topic to remove
     */
    public void removeTopic(Topic topic) {
        this.topics.remove(topic);
    }

    /**
     * Returns level of this forum. Level is a number of forum ancestors: for
     * root level forum this will be 0 and so on.
     *
     * @return forum level
     */
    public int getLevel() {
        int level = 0;
        Forum forum = this;
        while (forum.getParent() != null) {
            level++;
            forum = forum.getParent();
        }
        return level;
    }

    /**
     * Returns number of topics in this forum.
     *
     * @return number of topics
     */
    public Integer getNumberOfTopics() {
        return numberOfTopics;
    }

    /**
     * Sets number of topics in this forum.
     *
     * @param numberOfTopics number to set
     */
    public void setNumberOfTopics(Integer numberOfTopics) {
        this.numberOfTopics = numberOfTopics;
    }

    /**
     * Returns number of replies in this forum.
     *
     * @return number of replies
     */
    public Integer getNumberOfReplies() {
        return numberOfReplies;
    }

    /**
     * Returns list of forum subscriptions.
     *
     * @return list of forum subscriptions
     * @hibernate.bag name="forumSubscriptions" inverse="true" lazy="true"
     * cascade="delete" outer-join="false"
	 * @hibernate.collection-key column="`forum_id`"
	 * @hibernate.collection-one-to-many class="com.blandware.atleap.model.forum.ForumSubscription"
     */
    public List getForumSubscriptions() {
        return forumSubscriptions;
    }

    /**
     * Sets list of forum subscriptions.
     *
     * @param forumSubscriptions list to set
     */
    public void setForumSubscriptions(List forumSubscriptions) {
        this.forumSubscriptions = forumSubscriptions;
    }

    /**
     * Adds a forum subscription to the list.
     *
     * @param forumSubscription the subscription to be added
     */
	public void addForumSubscription(ForumSubscription forumSubscription) {
		forumSubscription.setForum(this);
		forumSubscriptions.add(forumSubscription);
	}

    /**
     * Removes a forum subscription from the list.
     *
     * @param forumSubscription the subscription to be removed
     */
	public void removeForumSubscription(ForumSubscription forumSubscription) {
		forumSubscriptions.remove(forumSubscription);
	}

    /**
     * Sets number of replies in this forum.
     *
     * @param numberOfReplies number to set
     */
    public void setNumberOfReplies(Integer numberOfReplies) {
        this.numberOfReplies = numberOfReplies;
    }

    /**
     * Returns last post.
     *
     * @return last post
     */
    public Post getLastPost() {
        return lastPost;
    }

    /**
     * Sets last post.
     *
     * @param lastPost post to set
     */
    public void setLastPost(Post lastPost) {
        this.lastPost = lastPost;
    }

    /**
     * Returns subscribed users map.
     *
     * @return subscribed users map
     * @see #usersSubscribed
     */
    public Map getUsersSubscribed() {
        return usersSubscribed;
    }

    /**
     * Sets subscribed users map.
     *
     * @param usersSubscribed map to set
     * @see #usersSubscribed
     */
    public void setUsersSubscribed(Map usersSubscribed) {
        this.usersSubscribed = usersSubscribed;
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Forum)) return false;
        if (!super.equals(o)) return false;

        final Forum forum = (Forum) o;

        if (parent != null ? !parent.equals(forum.parent) : forum.parent != null) return false;
        if (position != null ? !position.equals(forum.position) : forum.position != null) return false;

        return true;
    }

    public int hashCode() {
        int result = super.hashCode();
        result = 29 * result + (parent != null ? parent.hashCode() : 0);
        result = 29 * result + (position != null ? position.hashCode() : 0);
        return result;
    }
}
